package com.fashion.service;

import com.fashion.dao.ColumnDao;
import com.fashion.exceptions.ColumnNotFoundException;
import com.fashion.model.News;
import com.fashion.model.NewsColumn;
import com.fashion.utils.ColumnTree;
import com.fashion.utils.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * User: juventus
 * Date: 11-5-3
 * Time: 下午4:33
 */
@Service("columnService")
public class ColumnServiceImpl implements ColumnService {
    private static final Logger logger = Logger.getLogger(ColumnServiceImpl.class);
//    private List<NewsColumn> flatColumns;
//    private List<NewsColumn> treeColumns;
    private long timeStamp = System.currentTimeMillis();
    private static final long interval = 1000 * 60 * 60;

    private ColumnDao columnDao;
    @Resource(name = "hibernateTemplate")
    private HibernateTemplate template;

    @Override
    public void saveOrUpdateColumn(NewsColumn column) {
        columnDao.saveOrUpdate(column);
    }

    @Override
    public List<NewsColumn> findAllFlatColumns() {
      /*  if (null != flatColumns && (System.currentTimeMillis() - timeStamp < interval)) {
            return flatColumns;
        }

        flatColumns = columnDao.find("from NewsColumn");
        timeStamp = System.currentTimeMillis();

        return flatColumns;*/

        return columnDao.find("from NewsColumn order by createDateTime asc");
    }

    @Override
    public void deleteColumnById(String id) {
        columnDao.deleteById(id, NewsColumn.class);
    }

    @Override
    public List<NewsColumn> findAllTreeColumns() {
       /* if (null != treeColumns && (System.currentTimeMillis() - timeStamp < interval)) {
            return treeColumns;
        }*/

        List<NewsColumn> columnList = findAllFlatColumns();
       /* treeColumns = orderColumns(columnList);
        timeStamp = System.currentTimeMillis();

        return treeColumns;*/

        return orderColumns(columnList);
    }

    public NewsColumn findColumnByUrl(String topColumnUrl, String columnUrl) throws ColumnNotFoundException {
        if (StringUtils.isNullOrEmpty(topColumnUrl)) {
            throw new ColumnNotFoundException("Top url is invalid " + topColumnUrl);
        }

        if (StringUtils.isNullOrEmpty(columnUrl)) {
            throw new ColumnNotFoundException("ColumnUrl url is invalid " + columnUrl);
        }

        NewsColumn top = findTopColumnByUrl(topColumnUrl);
        if (topColumnUrl.equals(columnUrl)) {
            return top;
        }

        List<NewsColumn> children = findAllFlatChildren(top);

        for (NewsColumn child : children) {
            if (child.getUrl().equalsIgnoreCase(columnUrl)) {
                return child;
            }
        }

        throw new ColumnNotFoundException("No such column for url: " + columnUrl);
    }

    public List<NewsColumn> findAllFlatChildren(NewsColumn top) {
        List<NewsColumn> allColumns = findAllFlatColumns();

        return findAllFlatChildrenFromList(top, allColumns);
    }

    @Override
    public List<NewsColumn> findUrlForPathColumn(NewsColumn column) {
        List<NewsColumn> allColumns = findAllFlatColumns();
        List<NewsColumn> columnTopology = new ArrayList<NewsColumn>();
        columnTopology.add(column);
        NewsColumn tempColumn = column;
        while (!StringUtils.isNullOrEmpty(tempColumn.getParentId())) {
            for (NewsColumn allColumn : allColumns) {
                if (allColumn.getId().equals(tempColumn.getParentId())) {
                    columnTopology.add(allColumn);
                    tempColumn = allColumn;
                }
            }
        }

        return createUrlPathsByColumnTopology(columnTopology);
    }

    @Override
    public boolean isValidUrl(String topColumnUrl, String columnUrl) {
        try {
            NewsColumn column = findColumnByUrl( topColumnUrl,  columnUrl);
            return true;
        } catch (ColumnNotFoundException e) {
            return false;
        }
    }

    protected List<NewsColumn> createUrlPathsByColumnTopology(List<NewsColumn> columnTopology) {
        List<NewsColumn> urlPaths = new ArrayList<NewsColumn>();
        StringBuilder url = new StringBuilder("http://");
        for (int i = columnTopology.size() - 1; i >= 0; i--) {
            NewsColumn column = columnTopology.get(i);
            url.append(column.getUrl());

            if (StringUtils.isNullOrEmpty(column.getParentId())) {
                url.append(".fengsung.com");
            }

            url.append("/");
            NewsColumn newsColumn = new NewsColumn();
            newsColumn.setName(column.getName());
            newsColumn.setUrl(url.toString());
            urlPaths.add(newsColumn);
        }

        return urlPaths;
    }

    protected List<NewsColumn> findAllFlatChildrenFromList(NewsColumn top, List<NewsColumn> allColumns) {
        List<NewsColumn> childrenColumns = new ArrayList<NewsColumn>();

        for (NewsColumn newsColumn : allColumns) {
            if (top.getId().equals(newsColumn.getParentId())) {
                childrenColumns.add(newsColumn);
                childrenColumns.addAll(findAllFlatChildrenFromList(newsColumn, allColumns));
            }
        }

        return childrenColumns;
    }

    protected NewsColumn findTopColumnByUrl(String columnUrl) {
        List<NewsColumn> tops = findAllTreeColumns();

        for (NewsColumn top : tops) {
            if (top.getUrl().equalsIgnoreCase(columnUrl)) {
                return top;
            }
        }

        throw new ColumnNotFoundException("No such top column for url: " + columnUrl);
    }

    @Deprecated
    public NewsColumn findColumnByName(String name) {
        DetachedCriteria criteria = DetachedCriteria.forClass(NewsColumn.class);
        criteria.add(Restrictions.eq("name", name));
        List<NewsColumn> columnList = template.findByCriteria(criteria);

        return columnList.get(0);
    }

    protected List<NewsColumn> orderColumns(List<NewsColumn> columnList) {
        List<NewsColumn> columns = new ArrayList<NewsColumn>();

        for (NewsColumn column : columnList) {
            if (null == column.getParentId() || column.getParentId().isEmpty()) {
                columns.add(column);
                findChildren(column, columnList);
            }
        }

        return columns;
    }

    protected void findChildren(NewsColumn parentColumn, List<NewsColumn> columnList) {
        String id = parentColumn.getId();
        for (NewsColumn column : columnList) {
            if (id.equals(column.getParentId())) {
                parentColumn.addChildColumn(column);
                findChildren(column, columnList);
            }
        }
    }

    public NewsColumn findColumnFromTree(List<NewsColumn> trees, NewsColumn target) {
        NewsColumn column;
        for (NewsColumn tree : trees) {
            if (tree.getId().equals(target.getId())) {
                return tree;
            }

            List<NewsColumn> children = tree.getChildrenColumns();
            if (children != null) {
                column = findColumnFromTree(children, target);
                if (column != null) {
                    return column;
                }
            }
        }

        return null;
    }

    public List<NewsColumn> getAllChildren(NewsColumn target) {
        List<NewsColumn> columns = findAllTreeColumns();
        NewsColumn column = findColumnFromTree(columns, target);
        if (column == null) {
            logger.info("There is no column " + target.getId() + " " + target.getName());
        }

        List<NewsColumn> allChildren = new ArrayList<NewsColumn>();
        List<NewsColumn> children = column.getChildrenColumns();

        if (children != null)
            for (int i = 0; i < children.size(); i++) {
                allChildren.add(children.get(i));
                allChildren.addAll(getAllChildren(children.get(i)));
            }

        return allChildren;
    }

    @Override
    public List<ColumnTree> convertToTrees(List<NewsColumn> newsColumns) {
        List<ColumnTree> columnTrees = new ArrayList<ColumnTree>();
        for (NewsColumn newsColumn : newsColumns) {
            ColumnTree columnTree = convertToTree(newsColumn);
            columnTrees.add(columnTree);
        }
        return columnTrees;
    }

    @Override
    public List<NewsColumn> findNewsColumnsByNews(News news) {
        String hql = "select new NewsColumn(c.id, c.parentId, c.name, c.createDateTime, c.url, c.title) from NewsColumn c, News n, NewsColumnItem i  where i.newsId=n.id and i.columnId=c.id and n.id=:id";
        Map<String, Object> parameters = new HashMap<String, Object>();
        parameters.put("id", news.getId());

        return columnDao.findItems(hql, parameters);
    }

    @Override
    public NewsColumn findTopColumn(NewsColumn column) {
        List<NewsColumn> columns = findAllFlatColumns();

        while (!StringUtils.isNullOrEmpty(column.getParentId())) {
            for (NewsColumn newsColumn : columns) {
                if (newsColumn.getId().equals(column.getParentId())) {
                    column = newsColumn;
                    break;
                }
            }
        }

        return column;
    }

    protected ColumnTree convertToTree(NewsColumn newsColumn) {
        ColumnTree columnTree = new ColumnTree();
        columnTree.setId(newsColumn.getId());
        columnTree.setText(newsColumn.getName());

        for (NewsColumn column : newsColumn.getChildrenColumns()) {
            ColumnTree childTree = convertToTree(column);
            columnTree.addChild(childTree);
        }

        return columnTree;
    }

    @Resource(name = "columnDao")
    public void setColumnDao(ColumnDao columnDao) {
        this.columnDao = columnDao;
    }

	@Override
	public List<NewsColumn> findColumns(String[] ids) {
		DetachedCriteria criteria = DetachedCriteria.forClass(NewsColumn.class);
        criteria.add(Restrictions.in("id", ids));
        return template.findByCriteria(criteria);
	}


}